package vip.liux.contracts.infrastructure.localmsg;

import org.apache.commons.lang3.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

public interface LocalMessageRepository {

    LocalMessageRepository INSTANCE = new InMemoryLocalMessageRepository();

    void save(final LocalMessageRecord record);

    void updateById(final LocalMessageRecord record);

    List<LocalMessageRecord> loadWaitRetryRecords(List<String> status, long nextRetryTime, int retryIntervalMinutes);

    class InMemoryLocalMessageRepository implements LocalMessageRepository {

        private final ConcurrentMap<String, LocalMessageRecord> CACHE = new ConcurrentHashMap<>();

        @Override
        public void save(LocalMessageRecord record) {
            record.setId(UUID.randomUUID().toString());
            CACHE.put(record.getId(), record);
        }

        @Override
        public void updateById(LocalMessageRecord record) {
            CACHE.computeIfPresent(record.getId(), (key, value) -> {
                if (StringUtils.isNotBlank(record.getFailReason())) {
                    value.setFailReason(record.getFailReason());
                }
                if (record.getStatus() != null) {
                    value.setStatus(record.getStatus());
                }
                if (record.getRetryTimes() != null) {
                    value.setRetryTimes(record.getRetryTimes());
                }
                if (record.getNextRetryTime() != null) {
                    value.setNextRetryTime(record.getNextRetryTime());
                }
                value.setLastModificationTime(LocalDateTime.now());
                return value;
            });
        }

        @Override
        public List<LocalMessageRecord> loadWaitRetryRecords(List<String> status, long nextRetryTime, int retryIntervalMinutes) {
            long now = System.currentTimeMillis();
            return CACHE.values().stream()
                    .filter(r -> status.contains(r.getStatus()))
                    .filter(r -> r.getNextRetryTime() != null && r.getNextRetryTime() <= now)
                    .collect(Collectors.toList());
        }
    }
}

